// Proxy ES6 构造函数

// defineProperty 劫持数据 -> 给对象进行扩展 -> 属性进行设置

// let obj = {
  // a: 1,
  // b: 2
// }
// defineProperty(obj, '属性名', {

// })


// 不对对象本身进行处理，而是进行代理返回一个代理对象
// var proxy = new Proxy(obj)

// ---------------------------------------------------------------


// let obj = new Proxy(target, handler);

// target 目标对象 要进行处理的对象
// handler 容器 无数可以处理对象属性的方法

// 可自定义 对象属性的获取、赋值、枚举、函数调用等功能

// 用法：

// 对象
// var target = {
//   a: 1,
//   b: 2
// }

// let proxy = new Proxy(target, {
//   get (target, prop) {
//     return 'This is property value ' + target[prop]
//   },

//   set (target, prop, value) {
//     console.log('set: '+ target[prop] + '--> ' + value)
//     target[prop] = value
//   },

// });


// console.log(proxy.a)
// console.log(target.a)
// proxy.b = 3
// // 因为是进行代理， 代理的变了，原本的也要变，对代理的 进行操作
// console.log('proxy', proxy)
// console.log('target', target)

// 数组
// let arr = [
//   {name: '小明', age: 18},
//   {name: '小红', age: 46},
//   {name: '小青', age: 12},
//   {name: '小蓝', age: 21},
//   {name: '小紫', age: 25},
//   {name: '小黑', age: 34},
//   {name: '小军', age: 27}
// ]

// let persons = new Proxy(arr, {
//   get (target, prop) {
//     console.log('This is property value ' + target[prop].name + ' and ' + target[prop].age)
//     return target[prop]
//   },

//   set (target, prop, value) {
//     target[prop] = value
//   },

// });


// console.log(persons[0])
// // console.log(arr[0])
// arr[2] = {name: '小李', age: 99}

// console.log('persons', persons)
// console.log('arr', arr)


// 函数
// let fn = function() {
//   console.log('I am a function.')
// }
// fn.a = 123

// let newFn = new Proxy(fn, {
//   get (target, prop) {
//     return 'This is Proxy value ' + target[prop] 
//   }

// });

// console.log(newFn.a)




// ------------------------------------------------------

// 自定义 proxy 函数
function MyProxy(target, handler) {

  let _target = deepClone(target) // 深拷贝一份要处理的对象

  Object.keys(_target).forEach(key => { // 循环监听处理每一个属性
    Object.defineProperty(_target, key, {
      get() { // 判断如果handler存在get方法就调用
        return handler.get && handler.get(target, key)
      },
      set(newVal) {
        handler.set && handler.set(target, key, newVal)
      }
    })
  })
  return _target; // 把最终处理的结果返回出去

  function deepClone (org, tar) { // 深拷贝
    var tar = tar || {},
        toStr = Object.prototype.toString,
        arrType = '[Object Array]';
    for (var key in org) {
      if (org.hasOwnProperty(key)) {
        if (typeof(org[key]) === 'object' && org[key] !== null) {
          tar[key] = toStr.call(org[key]) === arrType ? [] : {};
          deepClone(org[key], tar[key])
        } else {
          tar[key] = org[key]
        }
      }
    }
    return tar;
  }
}

// let target = {
//   a: 1,
//   b: 2
// }

// let proxy = new MyProxy(target, {
//   get(target, prop) {
//     console.log('Get: ' + prop + ' = ' + target[prop])
//     return target[prop]
//   },
//   set(target, prop, value) {
//     console.log('Set: ' + prop + ' = ' + value)
//     target[prop] = value
//   }
// })

// let proxy = new Proxy(target, {
//   get(target, prop) {
//     return target[prop]
//   },
//   set(target, prop, value) {
//     target[prop] = value
//   }
// })

// console.log(proxy.a)
// proxy.b = 3
// console.log(proxy.b)





// ------------------------------------------------------


// let target = {
//   a: 1,
//   b: 2
// }

// let proxy = new Proxy(target, {
//   get(target, prop) {
//     console.log('Get: ' + prop + ' = ' + target[prop])
//     return target[prop]
//   },

//   set(target, prop, value) {
//     console.log('Set: ' + prop + ' = ' + value)
//     target[prop] = value
//   },

//   has(target, prop) {
//     console.log('has: '+ target[prop])
//     // return target[prop]
//   },

//   deleteProperty(target, prop) {
//     delete target[prop]
//   }
// })

// console.log('a' in proxy) // false 因为proxy为代理出来的对象，本身是不具有这个属性，只是存在于内置的 [[Target]] 里面
// console.log(proxy)
// console.log(proxy.a)
// proxy.b = 3
// console.log(proxy.b)

// delete proxy.b;
// console.log(proxy)
// console.log(target)

// Proxy handler(内部的方法) --> 转发给了 target(要处理的对象)
// handler方法可以复写任意的方法(重写Proxy上的默认方法)
// 当外界通过 Proxy 访问 target对象的属性 时，会经过handler上的每一个
// 对应的方法， 就可以通过重写Proxy上的默认方法来做一些操作

// 通过代理target的方式 先去操作Proxy 再通过Proxy代理内部的方法去操作 target






// ------------------------------------------------------

let target = {
  a: 1,
  b: 2
}

let proxy = new Proxy(target, {
  get(target, prop) { 
    // return target[prop]

    // Reflect 反射 内置对象 方法集合的容器(Object14种方法，除了枚举有13种)
    // 很多对象的方法都是直接放在Object上但是操作数组、函数，就不合理
    return Reflect.get(target, prop) // 用方法来取值更加合理
  },

  set(target, prop, value) {
    // target[prop] = value
    // Reflect.set(target, prop, value)
    const isOk = Reflect.set(target, prop, value)
    if (isOk) {
      console.log('Set successfully')
    }
  }
})

console.log(proxy.a)
proxy.b = 4
console.log(proxy.b)


// object 广义的对象 Object 狭义的对象
// Object 是一个构造器 构造对象的
// Object.prototype
// Array.protoptype

// Reflect 为ES6全局的内置对象， 是内置方法的集合容器，
// 直接保存静态方法，不需要实例化，未来会逐步放入更多的方法

// Reflect --> Reflect.has(obj, 'a');
// Object --> ('a' in obj)

// Object 往往会抛出异常 需要用到try catch来捕获
// Reflect 一般会返回一个状态


